/**
 * {@author Stefan Dröge}
 */
package de.sdroege.memorizer;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.Credentials;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.app.Service;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.sqlite.SQLiteDatabase;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.preference.PreferenceManager;
import android.util.Log;

public class EdiscioClient extends Service
{
  private static final String TAG = "EdsicioClient";
  private static CardBoxDbAdapter mDbHelper;
  //private Thread downloadThread;
  private DownloadTask initialDownloadTask;
  private Thread mEdiscioClientThread;
  private static ExecutorService executor;

  private static SharedPreferences preferences;
  private static String ediscioUser;
  private static String ediscioPW;

  // TODO Fehler abfangen wenn Passwort/Benutzername falsch

  // #####################################################
  // Inherited Methods

  @Override
  public void onCreate()
  {
    // TODO Auto-generated method stub
    super.onCreate();
    // Get username and password from the preferences
    preferences = PreferenceManager.getDefaultSharedPreferences( this );
    ediscioUser = preferences.getString( "username", "Benutzername" );
    ediscioPW = preferences.getString( "passwd", "Passwort" );
    // ###################################
    // Create / open database
    mDbHelper = new CardBoxDbAdapter(this);
    mDbHelper.open();
    // #####################################
    // create a Thread Pool for the download and Database tasks
    executor = Executors.newCachedThreadPool();
  }

  @Override
  public void onStart(Intent intent, int startId)
  {
    // TODO Auto-generated method stub
    super.onStart( intent, startId );
    // Download the overview of the CardBoxes
    initialDownloadTask = new DownloadTask();
    // execute the Download Task in the Thread Pool
    executor.execute( initialDownloadTask );
    //    mEdiscioClientThread = new Thread()
    //    {
    //      public void run()
    //      {
    //        downloadThread = new DownloadTask();
    //        downloadThread.start();
    //        try
    //        {
    //          downloadThread.join();
    //        } catch ( InterruptedException e )
    //        {
    //          // TODO Auto-generated catch block
    //          Log.d( TAG, e.getMessage() );
    //        }
    //        downloadReady.sendEmptyMessage( 0 );
    //      }
    //};
    mEdiscioClientThread.start();

  }

  @Override
  public IBinder onBind(Intent intent)
  {
    // TODO Auto-generated method stub
    return null;
  }

  /**
   * This Handler gets called, when a download has finished.
   */
  private final Handler downloadReady = new Handler()
  {

    @Override
    public void handleMessage(Message msg)
    {
      // TODO Auto-generated method stub
      // Handler soll Funktion zum speichern in der DB aufrufen.
      super.handleMessage( msg );
      mDbHelper.updateOrCreate((JSONObject)msg.obj);
      // TODO in thread/runnable verpacken
      if EdiscioClient( msg.what == DownloadTask.MODE_GET_CARDBOXES ) 
      {
        mDbHel
      }
      // DownloadThreadList.remove(0);
      /*
       * try { mEdiscioClientThread.join(); } catch (InterruptedException e) {
       * Log.d(TAG, e.getMessage()); } mEdiscioClientThread = null;
       */

    }

  };

  // #####################################################
  // 

  /**
   * This class creates a new Thread for downloading JSON data from ediscio.
   * 
   * @author Stefan Dröge
   * 
   */
  //private class DownloadTask extends Thread
  private class DownloadTask implements Runnable
  {
    private static final int MODE_GET_CARDBOXES = 1;
    private static final int MODE_GET_CARDS     = 2;
    private static final String TAG = "DownloadTask";
    private final int mMode;
    private final Integer mCardBoxNr;
    private final Message mResult;
    // Set the base URL
    private final StringBuilder url = new StringBuilder( "http://www.ediscio.de/api/" );
    private JSONObject jsonResult;

    /**
     * This constructor provides a {@code DownloadTask} Thread which downloads
     * the CardBox which is given by {@link _cardboxNr} from Ediscio.
     * When the download is finished, the {@code downloadReady} Handler is
     * called.
     * 
     * @param _cardboxNr
     *          The number of the CardBox to download.
     */
    public DownloadTask(int _cardboxNr)
    {
      mMode = MODE_GET_CARDS;
      mCardBoxNr = _cardboxNr;
      // We use 'Message.obtain()' instead of 'new Message()' to obtain a
      // Message instance from the global pool, and thus avoiding the allocation
      // of new Message instances. Yeah Recycling ;-) Green Programming(TM) ^^
      mResult = Message.obtain();
    }

    /**
     * The default constructor provides a {@code DownloadTask} Thread which
     * downloads the set of CardBoxes from Ediscio. When the download is
     * finished, the {@code downloadReady} Handler is called.
     */
    public DownloadTask()
    {
      mMode = MODE_GET_CARDBOXES;
      mCardBoxNr = 0;
      mResult = Message.obtain();
    }

    @Override
    public void run()
    {
      String result = null;

      // Set the right URL for the download, depending on the parameters
      if ( mMode == MODE_GET_CARDS )
      {
        url.append( "cardbox/" + mCardBoxNr );
      } else
        url.append( "activecardboxes" );

      // create HTTP Client
      DefaultHttpClient httpClient = new DefaultHttpClient();

      // prepare HTTP GET Request
      HttpGet httpGet = new HttpGet( url.toString() );
      // add "accept" Request Header to demand the response in JSON format
      httpGet.addHeader( "accept", "application/json" );

      // Set credentials for the HTTP request
      Credentials creds = new UsernamePasswordCredentials( ediscioUser, ediscioPW );
      BasicCredentialsProvider credsprovider = new BasicCredentialsProvider();
      credsprovider.setCredentials( new AuthScope( "www.ediscio.de", 80, "Ediscio" ), creds );
      httpClient.setCredentialsProvider( credsprovider );

      HttpResponse response;
      try
      {
        response = httpClient.execute( httpGet );
        // TODO: HTTP-Status (z.B. 404) in eigener Anwendung
        // verarbeiten.
        // z.B. mit response.getStatusLine();

        Log.i( TAG, response.getStatusLine().toString() );

        // Get hold of the response entity
        HttpEntity entity = response.getEntity();

        // If the response does not enclose an entity, there is no need
        // to worry about connection release

        if ( entity != null )
        {
          InputStream instream = entity.getContent();
          try
          {

            BufferedReader reader = new BufferedReader( new InputStreamReader( instream ) );
            StringBuilder sb = new StringBuilder();

            String line = null;
            while ( (line = reader.readLine()) != null )
              sb.append( line );

            result = sb.toString();

            Log.i( TAG, result );

            jsonResult = new JSONObject( result );

          } finally // try
          {

            // Closing the input stream will trigger connection
            // release
            instream.close();

          }
        }
      } catch ( IOException ex )  // try
      {

        // In case of an IOException the connection will be released
        // back to the connection manager automatically
        // throw ex;
        // TODO
      } catch ( JSONException ex )
      {
        Log.d( TAG, ex.getMessage() );

      } catch ( RuntimeException ex )
      {

        // In case of an unexpected exception you may want to abort
        // the HTTP request in order to shut down the underlying
        // connection and release it back to the connection manager.
        httpGet.abort();
        throw ex;
      }

      // When HttpClient instance is no longer needed,
      // shut down the connection manager to ensure
      // immediate deallocation of all system resources

      httpClient.getConnectionManager().shutdown();

      mResult.obj = jsonResult;
      mResult.what = mMode;

      downloadReady.sendMessage( mResult );

    } // public void run()
  } // private class DownloadTask

} // public class EdiscioClient
